package com.common.file;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.IOException;
import java.util.Collection;

@Slf4j
public class FileTypeHandler {

    public static FileType getFileType(String base64){
        return getFileType(Base64.decodeBase64(base64));
    }
    public static FileType getFileType(byte[] fileBytes){
        String head = getFileHead(fileBytes).toUpperCase();
        for (FileType ft : FileType.values()) {
            if (StringUtils.startsWith(head, ft.getFileHead())){
                return ft;
            }
        }
        return null;
    }

    private static String getFileHead(byte[] fileBytes){
        byte[] head = new byte[28];
        System.arraycopy(fileBytes,0,head,0,Integer.min(fileBytes.length, 28));
        return Hex.encodeHexString(head);
    }

    public static void main(String[] args) {
        Collection<File> files = FileUtils.listFiles(new File("D:\\Test\\filetype"),null, false);
        files.forEach(f->{
            try {
                String base64 = Base64.encodeBase64String(FileUtils.readFileToByteArray(f));
                String head = getFileHead(Base64.decodeBase64(base64)).toUpperCase();
                FileType fileType = getFileType(base64);
                System.out.println(f.getName()+"\t"+head+"===\t"+fileType);
            } catch (IOException e) {
                throw new RuntimeException(e);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
    }

}

@Slf4j
public class ImageUtils {

    private static final ThreadLocal<Map<String, ImageReader>> IMAGE_READER_CACHE =
            ThreadLocal.withInitial(HashMap::new);

    public static Dimension getImageOriginalSize(byte[] imageData) {
        // 1. 输入合法性校验（避免空指针/短数据）
        if (imageData == null || imageData.length < 8) { // 多数格式需至少8字节头
            log.warn("Invalid image data: null or too short (length={})",
                    imageData == null ? 0 : imageData.length);
            return new Dimension(0, 0);
        }

        // 2. 解析文件头，快速判断图片格式（比ImageIO自动探测快30%+）
        String format = getImageFormatByHeader(imageData);
        if (format == null) {
            log.warn("Unsupported image format (header bytes: {})",
                    bytesToHex(imageData, 0, 8)); // 打印前8字节便于排查
            return new Dimension(0, 0);
        }
        log.info("{}===>>>>>>>>>>>>>>>>>>>>>>>>>", format);

        // 3. 从线程缓存获取ImageReader（避免频繁创建）
        ImageReader reader = getCachedImageReader(format);
        if (reader == null) {
            log.warn("No ImageReader found for format: {}", format);
            return new Dimension(0, 0);
        }

        // 4. 读取元数据（核心优化：不加载完整图像）
        try (ByteArrayInputStream bis = new ByteArrayInputStream(imageData);
             ImageInputStream iis = ImageIO.createImageInputStream(bis)) {
            // 设为true：仅向前读取（元数据在流头部，无需回退），优化性能
            reader.setInput(iis, true, false);

            // 读取宽高（仅读元数据，不解码图像像素）
            int width = reader.getWidth(0);
            int height = reader.getHeight(0);

            // 尺寸合法性校验
            if (width <= 0 || height <= 0) {
                log.warn("Invalid image size: {}x{} (format={})", width, height, format);
                return new Dimension(0, 0);
            }

            return new Dimension(width, height);

        } catch (Exception e) {
            log.error("Failed to get image size (format={}, dataLength={})",
                    format, imageData.length, e);
            return new Dimension(0, 0);
        } finally {
            // 重置ImageReader，确保下次复用（清除旧输入流）
            reader.reset();
        }
    }

    /**
     * 解析文件头字节，判断图片格式
     * 支持：JPEG/PNG/GIF/BMP（可扩展WebP/TIFF等）
     */
    private static String getImageFormatByHeader(byte[] data) {
        // JPEG：文件头 0xFF D8 FF
        if (data.length >= 3) {
            int b1 = data[0] & 0xFF;
            int b2 = data[1] & 0xFF;
            int b3 = data[2] & 0xFF;
            if (b1 == 0xFF && b2 == 0xD8 && b3 == 0xFF) {
                return "jpeg";
            }
        }

        // PNG：文件头 0x89 50 4E 47 0D 0A 1A 0A
        if (data.length >= 8) {
            int b0 = data[0] & 0xFF;
            int b1 = data[1] & 0xFF;
            int b2 = data[2] & 0xFF;
            int b3 = data[3] & 0xFF;
            int b4 = data[4] & 0xFF;
            int b5 = data[5] & 0xFF;
            int b6 = data[6] & 0xFF;
            int b7 = data[7] & 0xFF;
            if (b0 == 0x89 && b1 == 0x50 && b2 == 0x4E && b3 == 0x47
                    && b4 == 0x0D && b5 == 0x0A && b6 == 0x1A && b7 == 0x0A) {
                return "png";
            }
        }

        // GIF：文件头 0x47 49 46 38（GIF8）
        if (data.length >= 4) {
            int b0 = data[0] & 0xFF;
            int b1 = data[1] & 0xFF;
            int b2 = data[2] & 0xFF;
            int b3 = data[3] & 0xFF;
            if (b0 == 0x47 && b1 == 0x49 && b2 == 0x46 && (b3 == 0x38)) {
                return "gif";
            }
        }

        // BMP：文件头 0x42 4D（BM）
        if (data.length >= 2) {
            int b0 = data[0] & 0xFF;
            int b1 = data[1] & 0xFF;
            if (b0 == 0x42 && b1 == 0x4D) {
                return "bmp";
            }
        }

        // 扩展支持：WebP（需引入twelvemonkeys依赖）
        // if (data.length >= 12 && data[8] == 'W' && data[9] == 'E' && data[10] == 'B' && data[11] == 'P') {
        //     return "webp";
        // }

        return null;
    }

    /**
     * 从线程缓存获取ImageReader，不存在则创建并缓存
     */
    private static ImageReader getCachedImageReader(String format) {
        Map<String, ImageReader> readerMap = IMAGE_READER_CACHE.get();
        ImageReader reader = readerMap.get(format);

        if (reader == null) {
            // 从ImageIO获取对应格式的Reader（SPI机制）
            Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName(format);
            if (readers.hasNext()) {
                reader = readers.next();
                readerMap.put(format, reader); // 缓存到当前线程
            }
        }

        return reader;
    }

    /**
     * 字节数组转16进制字符串（用于日志打印文件头）
     */
    private static String bytesToHex(byte[] data, int start, int len) {
        if (data == null || start < 0 || len <= 0 || start + len > data.length) {
            return "invalid";
        }
        StringBuilder sb = new StringBuilder();
        for (int i = start; i < start + len; i++) {
            sb.append(String.format("%02X ", data[i] & 0xFF));
        }
        return sb.toString().trim();
    }


}

